import 'dart:collection';
import 'dart:convert';
import 'dart:io';

import 'package:crypto/crypto.dart';

import 'package:dio/dio.dart';
import 'package:dio/io.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_syt/starter/http/http_log_interceptor.dart';
import 'package:flutter_syt/starter/http/request_interceptor.dart';
import 'package:intl/intl.dart';
import 'package:flutter_syt/application.dart';
import 'package:flutter_syt/datas/user_info.dart';
import 'package:flutter_syt/utils/utils_dlog.dart';
import 'package:uuid/uuid.dart';

import 'net_error.dart';

/// HTTP 请求类
class HttpManager {
  static var shared = HttpManager._();

  // static String get version {
  //   try {
  //     return appContext.packageInfo.version;
  //   } catch (e) {}
  //   return '1.0.0';
  // }

  final Dio _dio = Dio(BaseOptions(
      sendTimeout: const Duration(seconds: 10),
      receiveTimeout: const Duration(seconds: 10)));
  BuildContext? context;
  String Function() findProxy = () {
    // return "PROXY 192.168.31.177:8866";
    return "DIRECT"; //"PROXY 192.168.1.20:8888"
  };

  // Future<RequestOptions> Function(RequestOptions) onRequest = (options) async {
  //   var lang = Intl.getCurrentLocale();
  //   appContext.storage.setString('lang', lang);
  //   options.headers["mid"] = 1;
  //   options.headers["Authorization"] = UserInfo.me.token;
  //   DLog('UserInfo.me.token ${UserInfo.me.token}');
  //   options.headers["lang"] = lang;
  //   options.headers["OS"] = Platform.isIOS ? "ios" : "android";
  //   options.headers["VERSION"] = version;
  //
  //   if (Platform.isIOS) {
  //     options.headers["DEVICE"] = "${appContext.iOSInfo.model}";
  //     options.headers["DEVICE-VERSION"] = "${appContext.iOSInfo.systemVersion}";
  //   } else {
  //     options.headers["DEVICE"] = "${appContext.andriodInfo.model}";
  //     options.headers["DEVICE-VERSION"] =
  //         "${appContext.andriodInfo.version.release}";
  //   }
  //   options.headers["DEVICE-NETWORK"] = appContext.connectionStatus.toString();
  //   options.headers["DEVICE-LOCATION"] = '';
  //   options.headers['timestamp'] =
  //       (DateTime.now().millisecondsSinceEpoch ~/ 1000) - appContext.timeStamp;
  //   options.headers['nonce'] = Uuid().v1();
  //   options.headers['source'] = 'app';
  //
  //   options.headers['signature'] = headerToSignature(options);
  //   return options;
  // };
  //
  // static String headerToSignature(RequestOptions options) {
  //   // Map map = options.headers;
  //
  //   Map lowerMap = {};
  //   options.headers.keys.toList().forEach((element) {
  //     lowerMap[element.toString().toUpperCase()] = options.headers[element];
  //   });
  //   lowerMap.remove('CONTENT-TYPE');
  //
  //   // if (options.data != null && options.data is Map) {
  //   //   lowerMap.addAll(options.data);
  //   // }
  //   // if (options.method == "GET") {
  //   //   Uri uri = Uri.parse(options.path);
  //   //   lowerMap.addAll(uri.queryParameters);
  //   // } else if (options.method == "PUT") {
  //   //   // DLog(options.headers);
  //   // }
  //
  //   lowerMap.forEach((key, value) {
  //     lowerMap[key] =
  //         value.toString().replaceAll(' ', '').replaceAll('null', '');
  //   });
  //
  //   SplayTreeMap splayTreeMap = SplayTreeMap.from(lowerMap);
  //   var json = jsonEncode(splayTreeMap);
  //   json = json + '&secretKey=d93a5def7511da3d0f2d171d9c344e91';
  //   Digest digest = md5.convert(utf8.encode(json));
  //
  //   return digest.toString().toUpperCase();
  // }

  Response Function(Response) onResponse = (response) {
    debugPrint("url - ${response.realUri} data - ${response.data}");
// DLog(response.data);
// DLog("response.data['code'] == 200 ${response.data['code'] == 200}");
    Map<String, dynamic> data = response.data;
    String status = data["message"];
    if (status.toUpperCase() == "OK") {
      response.data = response.data["data"] ?? response.data;
      return response;
    }

    String errorCode = "${data["code"]}";
    if (outLoginCodes.contains(errorCode) ||
        authFailCodes.contains(errorCode)) {
      // OnlineGlobalData.shared.clean();
      UserInfo.clean();
      try {
        Navigator.of(appContext.context!).popUntil((route) => route.isFirst);
      } catch (e) {}
    }
    var errorMessage = "${data["message"]}";
    if (errorMessage == "null") errorMessage = "请求错误";
    throw NetError(errorMessage);
  };

  HttpManager._() {
    try {
      var adapter = _dio.httpClientAdapter as IOHttpClientAdapter;
      adapter.createHttpClient = () {
        // if (appContext.provider.isProd || appContext.provider.isDebug) {
        SecurityContext sc = SecurityContext();
        sc.setTrustedCertificatesBytes(appContext.cerBytes);
        HttpClient client = HttpClient(context: sc);
        // client.findProxy = (uri) {
        //   return findProxy();
        // };
        client.badCertificateCallback =
            (X509Certificate cert, String host, int port) {
          return true;
        };
        return client;
        // }else {
        //   client.badCertificateCallback =
        //       (X509Certificate cert, String host, int port) {
        //     return true;
        //   };
        //   client.findProxy = (uri) {
        //     return findProxy();
        //   };
        // }
      };
    } catch (e) {}
    _dio.interceptors.add(RequestInterceptor());
    if (!const bool.fromEnvironment("dart.vm.product")) {
      _dio.interceptors.add(HttpLogInterceptor());
    }
    _dio.interceptors.add(
      InterceptorsWrapper( onResponse: (response, handler) {
        var custom = onResponse(response);
        handler.next(custom);
      }, onError: (DioError e, handler) {
        if (e.response != null) {
          Map<String, dynamic> data = Map();
          try {
            data = e.response?.data;
          } catch (n) {}

          String errorCode = "${data["code"]}";
          if (outLoginCodes.contains(errorCode) ||
              authFailCodes.contains(errorCode)) {
            // OnlineGlobalData.shared.clean();
            UserInfo.clean();
            // customShowToast(status);
          }
        }
        handler.next(e);
      }),
    );
  }

  request(String method, String url,
      {Map<String, dynamic>? params,
      FormData? formData,
      String? contentType}) async {
    var options = Options(method: method);
    if (contentType != null) {
      options.contentType = contentType;
    }

    debugPrint("method = $method , url = $url , parmas = $params");
    var response;
    // try {
    // SplayTreeMap
    if (formData != null) {
      response = await _dio.request(url, data: formData, options: options);
    } else {
      response = await _dio.request(url, data: params, options: options);
    }

    // _dio.download(urlPath, savePath)

    //   return response.data;
    // } catch (e) {
    //   String str = await UtilsOther.showCustomShowError(e);
    //   return str;
    // }

    return response.data;
  }

  // download(
  //   String path,
  //   String savePath, {
  //   void Function(int, int)? onReceiveProgress,
  // }) async {
  //   // _dio.request(path)
  //   await _dio.download(path, savePath, onReceiveProgress: onReceiveProgress);
  //   // response = await _dio.request(, data: params, options: options);
  // }

  del(String path, {Map<String, dynamic>? params}) async {
    return request("DELETE", _buildUrl(path), params: params);
  }

  post(
    String path, {
    Map<String, dynamic>? params,
    FormData? formData,
  }) async {
    return request("POST", _buildUrl(path), params: params);
  }

  put(String path, {Map<String, dynamic>? params}) async {
    return request("PUT", _buildUrl(path), params: params);
  }

  get(String path, {Map<String, dynamic>? params}) async {
    return request("GET", path.startsWith('http') ? path : _buildUrl(path),
        params: params);
  }

  delete(String path, {Map<String, dynamic>? params}) async {
    return request("DELETE", path.startsWith('http') ? path : _buildUrl(path),
        params: params);
  }

  upload(String path, String filePath,
      {String fileName = "default.jpg"}) async {
    return request(
      "POST",
      _buildUrl(path),
      formData: FormData.fromMap(
        {
          'file': await MultipartFile.fromFile(
            filePath,
            filename: fileName,
          ),
        },
      ),
      contentType: "multipart/form-data",
    );
  }

  _buildUrl(String path) {
    return "${appContext.provider.apiUrl}$path";
  }
}
